package interceptcrossing.command;

import java.util.LinkedList;
import java.util.List;

public class CommandManager {

	private List<Command> undoCommands;
	private List<Command> redoCommands;
	private List<Listener> listeners;

	public CommandManager() {
		this.listeners = new LinkedList<Listener>();
		this.undoCommands = new LinkedList<Command>();
		this.redoCommands = new LinkedList<Command>();
	}

	public void reset() {
		this.undoCommands.clear();
		this.redoCommands.clear();
	}

	public void doCommand(Command cmd) {
		this.redoCommands.clear();
		this.undoCommands.add(cmd);

		cmd.doCommand();

		for (Listener listener : listeners) {
			listener.commandDone(this, cmd);
		}
	}

	public boolean canUndo() {
		return !this.undoCommands.isEmpty();
	}

	public void undo() {
		if (this.canUndo()) {
			Command cmd = this.undoCommands.get(this.undoCommands.size() - 1);
			this.undoCommands.remove(cmd);
			this.redoCommands.add(cmd);

			cmd.undoCommand();

			for (Listener listener : listeners) {
				listener.commandUndone(this, cmd);
			}
		}
	}

	public Command getPreviousCommand() {
		return this.canUndo() ?
			this.undoCommands.get(this.undoCommands.size() - 1) : null;
	}

	public boolean canRedo() {
		return !this.redoCommands.isEmpty();
	}

	public void redo() {
		if (this.canRedo()) {
			Command cmd = this.redoCommands.get(this.redoCommands.size() - 1);
			this.redoCommands.remove(cmd);
			this.undoCommands.add(cmd);

			cmd.doCommand();

			for (Listener listener : listeners) {
				listener.commandRedone(this, cmd);
			}
		}
	}

	public Command getNextCommand() {
		return this.canRedo() ?
			this.redoCommands.get(this.redoCommands.size() - 1) : null;
	}

	public void addListener(Listener listener) {
		if (!this.listeners.contains(listener)) {
			this.listeners.add(listener);
		}
	}

	public void removeListener(Listener listener) {
		if (this.listeners.contains(listener)) {
			this.listeners.remove(listener);
		}
	}


	public static interface Listener {

		public void commandDone(CommandManager cmdManager, Command command);

		public void commandUndone(CommandManager cmdManager, Command command);

		public void commandRedone(CommandManager cmdManager, Command command);
	}
}
